package tr.com.netgis.pojo;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import tr.com.netgis.util.RotatingNGLocation;
import tr.com.netgis.util.Status;
import tr.com.netgis.util.StatusSpeedStrategy;
import tr.com.netgis.util.StatusSpeedStrategyLast2Locations;
import tr.com.netgis.util.Utility;
import android.location.Location;
import android.location.LocationManager;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * 
 * @author NetGis
 *
 */
public class NGLocation implements Parcelable, Comparable<NGLocation> {

	public static final byte SENT = 1;
	public static final byte UNSENT = 0;
	public static final byte FORLOG = 3;
	
	/**
	 * for database
	 */
	private int _id;
	
	/**
	 * Lokasyonun sunucuya gönderilip gönderilmeyeceğini gösterir<br>
	 * 
	 * @return
	 */
	public boolean needToBeSent (){
		return this._location !=  null;
	}
	
	public boolean isSent() {
		return sent == (byte)1;
	}

	public byte getSent() {
		return sent;
	}

	public void setSent(byte sent) {
		this.sent = sent;
	}

	public static final Creator<NGLocation> CREATOR = new Creator<NGLocation>() {

		@Override
		public NGLocation createFromParcel(Parcel source) {
			return new NGLocation(source);
		}

		@Override
		public NGLocation[] newArray(int size) {
			return new NGLocation[size];
		}

	};	
	
	private double lat;
	private double lon;
	private long tarihSaat; //location'ın alınma tarihi
	private float speed;
	private Status status;
	private long date; //NGLocation'ı olusturma tarihi
	private Map<String, String> nameValues;
	private String provider;

	
	public String getProvider () {
		return this.provider;
	}
	
	public void setProvider (String provider) {
		this.provider = provider;
	}
	
	/**
	 * service'e gönderilip gönderilmediğini tutar
	 */
	private byte sent = 0;
	
	
	public void setSpeed (float speed){
		this.speed = speed;
	}
	
	public Status getStatus (){
		return status;
	}
	
	public void setStatus (Status status){
		this.status = status;
	}
	
	public double getLat() {
		return lat;
	}

	public void setLat(double lat) {
		this.lat = lat;
	}

	public double getLon() {
		return lon;
	}

	public void setLon(double lon) {
		this.lon = lon;
	}

	public long getTarihSaat() {
		return tarihSaat;
	}

	public void setTarihSaat(long tarihSaat) {
		this.tarihSaat = tarihSaat;
	}

	public float getSpeed() {
		return speed;
	}
	
	public String getSpeedView() {
		if (Status.HAREKET_EDIYOR.equals(status)) {
			int speed = Math.round(getSpeed());
			String sSpeed = Integer.toString(speed);
			return sSpeed + " km/sa";			
		}
		return "";
	}
	
	StatusSpeedStrategy strategy = new StatusSpeedStrategyLast2Locations();
	
	/**
	 * calculates speed and status
	 * as km/h
	 * @return
	 */
	public void calculateSpeedAndStatus (RotatingNGLocation lastNLocations/*List<NGLocation> lastNLocationList*/){
		this.setSpeed(strategy.calculateSpeed(this, lastNLocations));
		this.setStatus(strategy.determineStatus(this, lastNLocations));
	}

	public long getDate() {
		return date;
	}
	
	private Double _distance = null;
	
	/**
	 * km
	 * @return
	 */
	public double getDistance(){
		/*
		if (this.previousLocation != null) {
			if (_distance == null)
				_distance = Utility.distance(this, this.previousLocation);
		} else {
			return .0;
		}
		*/
		return _distance;
	}
	
	/**
	 * Yaratılma tarihi
	 * @param date
	 */
	public void setDate(long date) {
		this.date = date;
	}

	public String toString (){
		SimpleDateFormat sdf = Utility.createSimpleDateFormat();
		return MessageFormat.format("Yaratılma Tarihi:{0}\n" +
			"Konum Tarihi:{1}\n" +
			"Lat: {2}\n" +
			"Lon: {3}\n" +
			"Hız: {4}\n" +
			"Durum: {5} sent:({6})\n" +
			"Provider: {7}", 
			sdf.format(this.date),
			sdf.format(new Date(this.tarihSaat)),
			Double.toString(this.lat),
			Double.toString(this.lon),
			Float.toString(this.speed),
			this.status,
			this.sent,
			this.provider
		);
	}
	
	public boolean isRetrieved() {
		return this.tarihSaat != 0;
	}	

	private Location _location;

	public NGLocation() {
		this.lat = 99999999;
		this.lon = 99999999;
		this.speed = 0;
		this.provider = "";
	}
	
	public NGLocation(Location location) {
		super();
		this._location = location;
		if (this._location != null) {
			this.date = new Date().getTime();
			this.lat = location.getLatitude();
			this.lon = location.getLongitude();
			this.tarihSaat = location.getTime();
			this.status = Status.DURDU;
			this.speed = location.hasSpeed() ? location.getSpeed() : -1;
			this.provider = location.getProvider();
		}
	}
	
	public boolean isNetwork (){
		return LocationManager.NETWORK_PROVIDER.equals(this.provider);
	}

	public boolean isGPS (){
		return LocationManager.GPS_PROVIDER.equals(this.provider);
	}

	private NGLocation(Parcel source) {
		lat = source.readDouble();
		lon = source.readDouble();
		tarihSaat = source.readLong();
		speed = source.readFloat();
		date = source.readLong();
		status = (Status) source.readSerializable();
		sent = source.readByte();
		provider = source.readString();
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeDouble(this.lat);
		dest.writeDouble(this.lon);
		dest.writeLong(this.tarihSaat);
		dest.writeFloat(this.speed);
		dest.writeLong(this.date);
		dest.writeSerializable(this.status);
		dest.writeByte(this.sent);
		dest.writeString(this.provider);
	}

	@Override
	public int compareTo(NGLocation another) {
		return new Long(this.tarihSaat).compareTo(new Long(another.tarihSaat));
	}

	@Override
	public boolean equals(Object o) {
		if (!(o instanceof NGLocation)) {
			return false;
		}
		return this.tarihSaat == ((NGLocation)o).tarihSaat;
	}


	public Map<String, String> getNameValues() {
		return nameValues;
	}


	public void setNameValues(Map<String, String> nameValues) {
		this.nameValues = nameValues;
	}

	/**
	 * for database
	 * @return
	 */
	public int get_id() {
		return _id;
	}

	/**
	 * for database
	 * @param _id
	 */
	public void set_id(int _id) {
		this._id = _id;
	}


}
